package lion.framework.core.anno;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lion.dev.lang.MapJ;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * * 注解处理管理类
 *
 * <pre>
 * 	time: 2012-11-23 下午04:40:11
 * 	mail: hl_0074@sina.com
 * </pre>
 *
 * @author lion
 */
public class AnnotationProcessorManager {

	private static Map<Class<?>, IAnnotationProcessor> processorMap = new HashMap<>();
	private static Log log = LogFactory.getLog(AnnotationProcessorManager.class);
	public static final String ANNO_CONTEXT_TARGET = "target";
	public static final String ANNO_CONTEXT_CLASS = "class";

	public static void regist(Class<?> annoClass, IAnnotationProcessor processor) {

		processorMap.put(annoClass, processor);
	}

	private static IAnnotationProcessor getProcessor(Class<?> anno) {

		return processorMap.get(anno);
	}

	public static void processAnnotations(List<Class<?>> classes) {

		for (Class<?> clazz : classes) {
			try {
				dealClass(clazz);
			} catch (Throwable e) {
				log.warn(String.format("class [%s] skiped because %s", clazz.getName(), e.getMessage()));
			}
		}
	}

	private static void dealClass(Class<?> clazz) {

		MapJ ctx = new MapJ();
		ctx.put(ANNO_CONTEXT_CLASS, clazz);

		initClassAnno(ctx, clazz);
		initFieldAnno(ctx, clazz);
		initMethodAnno(ctx, clazz);
	}

	private static void initMethodAnno(MapJ ctx, Class<?> clazz) {

		for (Method m : clazz.getDeclaredMethods()) {
			ctx.put(ANNO_CONTEXT_TARGET, m);
			Annotation[] annos = m.getAnnotations();
			if (annos != null && annos.length > 0) {
				for (Annotation anno : annos) {

					IAnnotationProcessor processor = getProcessor(anno.getClass().getInterfaces()[0]);
					if (processor == null) {
						continue;
					}

					try {
						processor.processe(ctx, anno);
					} catch (Exception e) {
						if (log.isErrorEnabled()) {
							log.error("init system error", e);
						}
					}
				}
			}
		}
		ctx.remove(ANNO_CONTEXT_TARGET);
	}

	private static void initFieldAnno(MapJ ctx, Class<?> clazz) {

		for (Field field : clazz.getDeclaredFields()) {
			ctx.put(ANNO_CONTEXT_TARGET, field);
			Annotation[] annos = field.getAnnotations();
			if (annos != null && annos.length > 0) {
				for (Annotation anno : annos) {
					IAnnotationProcessor processor = getProcessor(anno.getClass().getInterfaces()[0]);
					if (processor == null) {
						continue;
					}

					try {
						processor.processe(ctx, anno);
					} catch (Exception e) {
						if (log.isErrorEnabled()) {
							log.error("init system error", e);
						}
					}
				}
			}
		}
		ctx.remove(ANNO_CONTEXT_TARGET);
	}

	private static void initClassAnno(MapJ ctx, Class<?> clazz) {

		ctx.put(ANNO_CONTEXT_TARGET, clazz);
		Annotation[] annos = clazz.getAnnotations();
		if (annos != null && annos.length > 0) {
			for (Annotation anno : annos) {
				IAnnotationProcessor processor = getProcessor(anno.getClass().getInterfaces()[0]);
				if (processor == null) {
					continue;
				}

				try {
					processor.processe(ctx, anno);
				} catch (Exception e) {
					if (log.isErrorEnabled()) {
						log.error("init system error", e);
					}
				}
			}
		}
		ctx.remove(ANNO_CONTEXT_TARGET);
	}

}
